package com.ace.scenep.day0115;

import java.util.TreeMap;
import java.util.concurrent.*;

/**
 * 简单任务队列实现
 * 支持任务优先级和单线程执行
 * 
 * 特点：
 * 1. 支持HIGH、MEDIUM、LOW三个优先级
 * 2. 相同优先级的任务按照提交时间FIFO执行
 * 3. 使用单线程执行器确保任务串行执行
 * 4. 支持优雅关闭，确保所有任务都能执行完成
 */
public class MyTaskQueen {
    
    /**
     * 任务优先级枚举
     * HIGH(0): 最高优先级
     * MEDIUM(5): 中等优先级
     * LOW(10): 最低优先级
     * 数值越小，优先级越高
     */
    public enum Priority {
        HIGH(0),
        MEDIUM(5),
        LOW(10);
        
        private final int value;
        
        Priority(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
    }
    
    /**
     * 封装任务和优先级的包装类
     * 实现Comparable接口以支持优先级排序
     */
    private static class PriorityTask implements Comparable<PriorityTask> {
        private final Runnable task;        // 实际要执行的任务
        private final Priority priority;     // 任务的优先级
        private final long createTime;       // 任务创建时间戳，用于同优先级任务的FIFO排序

        TreeMap<String, Object> map = new TreeMap<>();
        public PriorityTask(Runnable task, Priority priority) {
            this.task = task;
            this.priority = priority;
            this.createTime = System.currentTimeMillis();
        }
        
        @Override
        public int compareTo(PriorityTask other) {
            // 优先级比较：数值小的优先级高
            int result = Integer.compare(this.priority.getValue(), other.priority.getValue());
            if (result == 0) {
                // 当优先级相同时，按照创建时间排序（先创建的先执行）
                return Long.compare(this.createTime, other.createTime);
            }
            return result;
        }
    }
    
    /**
     * 任务队列：使用优先级阻塞队列，自动按优先级排序
     * PriorityBlockingQueue是线程安全的无界优先级队列
     */
    private final PriorityBlockingQueue<PriorityTask> taskQueue = new PriorityBlockingQueue<>();
    
    /**
     * 执行器：使用单线程执行器确保任务按优先级顺序串行执行
     * 避免多线程并发执行导致的顺序问题
     */
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    
    /**
     * 运行状态标志：volatile确保多线程间的可见性
     * 例如:
     * 1. 线程A修改running=false要关闭队列时，没有volatile的话
     *    线程B可能看不到这个修改，继续处理任务
     * 2. 就像两个人在不同房间操作同一个开关
     *    volatile相当于让双方都能实时看到开关状态
     * 3. 或者像共享的记事本，volatile确保所有人看到最新内容
     * 没有volatile可能导致：
     * - 一个线程改了值，其他线程还在用旧值
     * - 关闭队列时其他线程无法及时停止
     * true: 队列正在运行
     * false: 队列已关闭
     */
    private volatile boolean running = true;
    
    public MyTaskQueen() {
        // 启动任务处理线程
        startTaskProcessor();
    }
    
    /**
     * 添加任务到队列
     * @param task 要执行的任务
     * @param priority 任务优先级
     */
    public void addTask(Runnable task, Priority priority) {
        if (!running) {
            throw new IllegalStateException("Task queue is shutdown");
        }
        taskQueue.offer(new PriorityTask(task, priority));
    }
    
    /**
     * 获取队列中待执行的任务数量
     */
    public int getPendingTaskCount() {
        return taskQueue.size();
    }
    
    /**
     * 启动任务处理线程
     * 在后台持续监控队列，按优先级顺序处理任务
     */
    private void startTaskProcessor() {
        executor.submit(() -> {
            while (running || !taskQueue.isEmpty()) {  // 继续处理直到队列关闭且所有任务处理完成
                try {
                    // 从队列中获取任务，最多等待100ms
                    // 使用超时等待避免永久阻塞，允许检查running状态
                    PriorityTask priorityTask = taskQueue.poll(100, TimeUnit.MILLISECONDS);
                    if (priorityTask != null) {
                        try {
                            priorityTask.task.run();
                        } catch (Exception e) {
                            // 捕获任务执行时的异常，避免影响其他任务的执行
                            e.printStackTrace();
                        }
                    }
                } catch (InterruptedException e) {
                    // 处理中断请求，通常发生在关闭时
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
    }
    
    /**
     * 优雅关闭任务队列
     * 1. 停止接收新任务
     * 2. 等待现有任务执行完成
     * 3. 如果超时（30秒）强制关闭
     */
    public void shutdown() {
        running = false;  // 标记队列为关闭状态
        try {
            // 关闭执行器并等待现有任务完成
            executor.shutdown();
            if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                // 超过30秒还未完成，强制关闭
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            // 处理中断请求
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}